package com.quarkdown.cli.creator

import com.quarkdown.cli.creator.content.ProjectCreatorInitialContentSupplier
import com.quarkdown.cli.creator.template.ProjectCreatorTemplatePlaceholders
import com.quarkdown.cli.creator.template.ProjectCreatorTemplateProcessorFactory
import com.quarkdown.core.pipeline.output.ArtifactType
import com.quarkdown.core.pipeline.output.OutputResource
import com.quarkdown.core.pipeline.output.TextOutputArtifact
import com.quarkdown.core.template.TemplateProcessor

/**
 * Generator of resources for a new Quarkdown project via [createResources].
 * Based on different properties, the resources and their content may vary.
 * @param templateProcessorFactory factory that generates the template for the main file
 * @param initialContentSupplier supplier of the initial content (code content and assets)
 * @param mainFileName name of the main file, without extension
 * @see DefaultProjectCreatorTemplateProcessorFactory
 * @see DefaultProjectCreatorInitialContentSupplier
 * @see EmptyProjectCreatorInitialContentSupplier
 */
class ProjectCreator(
    private val templateProcessorFactory: ProjectCreatorTemplateProcessorFactory,
    private val initialContentSupplier: ProjectCreatorInitialContentSupplier,
    private val mainFileName: String,
) {
    /**
     * @return the template processor created by [templateProcessorFactory],
     * with also the initial content inside, supplied by [initialContentSupplier]
     */
    private fun createTemplateProcessor(): TemplateProcessor {
        val template: TemplateProcessor = templateProcessorFactory.create()

        // Initial content is processed via the same template processor.
        val initialContentCode =
            initialContentSupplier.templateCodeContent
                ?.let { template.copy(text = it).process() }

        // Processed initial content and additional information are injected into the main template.
        template.optionalValue(ProjectCreatorTemplatePlaceholders.INITIAL_CONTENT, initialContentCode)
        template.optionalValue(ProjectCreatorTemplatePlaceholders.MAIN_FILE, mainFileName)

        return template
    }

    /**
     * @return a collection of resources generated by this project creator
     */
    fun createResources(): Set<OutputResource> {
        val main =
            TextOutputArtifact(
                mainFileName,
                this.createTemplateProcessor().process().trim(),
                ArtifactType.QUARKDOWN,
            )

        return buildSet {
            add(main)
            addAll(initialContentSupplier.createResources())
        }
    }
}
